package lib.relay;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.util.List;

import lib.relay.RegistRelayFunc.SignUpStatus;
import lib.relay.ThreadCtrlBase.ThreadRunListener;
import lib.relay.TimerCtrlBase.TimerRunListener;
import android.content.Context;
import android.os.Handler;
import android.os.Message;
import android.util.Log;

// import asus nat tunnel libraries
import com.asus.natapi.NatCallback;
import com.asus.natapi.NatConfig;
import com.asus.natapi.NatNativeAPI;

// Test Data for configurations
class CfgDataInit {
	// # Account
	public static String DEVICE_ID = "0010019000000000000083@aaerelay.asuscomm.com";
	public static String DEVICE_PWD = "001";

	// # Log
	// #
	// # Log level 0~6, 6=very detailed..1=error only, 0=disabled
	// # Default 4
	// # Log to filename. If this option isn't assigned, log is just output to
	// console.
	public static String LOG_FILE_PATH = "/sdcard/pjlog.txt";
	// # flag : 1 for Log append if log file exists, otherwise 0
	public static int LOG_FILE_FLAG = 0;
	public static int LOG_LOG_LEVEL = 4;

	// # SIP server info, add multiple servers
	public static String SIP_SRV = "122.248.227.43:5061";
	public static String SIP_SRV2 = "54.251.34.52:5061";
	public static String SIP_SRV3 = "54.251.197.15:5061";

	public static int USE_TLS = 0;
	public static int VERIFY_SERVER = 0; // verify server's certificate, since
	// v1.1.0.9

	// # Media
	// MAX recieved calls #Default 4, maximum 32
	public static int MAX_CALLS = 4;
	public static int FORCE_TO_USE_ICE = 1;

	// # Stun Server
	public static String STUN_SRV = "sgstun001.asuscomm.com";
	public static int USE_STUN = 1;// ****

	// # Turn Server
	// # 0:don't use turn
	// # 1:UAC and UAS use respective turn server
	// # 2:UAC and UAS both use UAC's turn server
	public static int USE_TURN = 2;
	public static String TURN_SRV = "54.251.198.216:80";
	public static String TURN_SRV2 = "54.251.198.216:80";
	// # Upnp
	// # 0:don't use upnp
	// # 1:use SDK select port
	// # 2:use user selected port, --user-port describes the local-external port
	// mappging
	public static int UPNP_FLAG = 1;
	public static int USER_PORT_CNT = 2;
	public static String[] LOCAL_DATA = { "4000", "81" };
	public static String[] EXTERNAL_DATA = { "4000", "81" };
	public static String[] LOCAL_CTL = { "4001", "82" };
	public static String[] EXTERNAL_CTL = { "4001", "82" };

	// # Tunnel
	// *** Eddy
	public static int SRV_PORT_CNT = 1;
	public static String[] LOCAL_PORT = { "7777" };
	public static String[] REMOTE_PORT = { "8088" };

	// public static String[] LOCAL_PORT = { "7777" };
	// public static String[] REMOTE_PORT = { "7777" };

}

class Natnl_Event {
	public static int NATNL_INV_EVENT_NULL = 0;
	/** < Before INVITE is sent or received */
	public static int NATNL_INV_EVENT_CALLING = 1;
	/** < After INVITE is sent */
	public static int NATNL_INV_EVENT_INCOMING = 2;
	/** < After INVITE is received. */
	public static int NATNL_INV_EVENT_EARLY = 3;
	/** < After response with To tag. */
	public static int NATNL_INV_EVENT_CONNECTING = 4;
	/** < After 2xx is sent/received. */
	public static int NATNL_INV_EVENT_CONFIRMED = 5;
	/** < After ACK is sent/received. */
	public static int NATNL_INV_EVENT_DISCONNECTED = 6;
	/** < Session is terminated. */

	public static int NATNL_SIP_EVENT_REG = 60000;
	/** < NATNL sip registration (login sip server) state */
	public static int NATNL_SIP_EVENT_UNREG = 60001;
	/** < NATNL sip unregistration (logout sip server) state */
	public static int NATNL_TNL_EVENT_KA_TIMEOUT = 60002;
	/** < NATNL tunnel or STUN keep-alvie timeout */
	public static int NATNL_TNL_EVENT_START = 60003;
	/** < NATNL tunnel start */
	public static int NATNL_TNL_EVENT_STOP = 60004;
	/** < NATNL tunnel stop */
	public static int NATNL_TNL_EVENT_NAT_TYPE_DETECTED = 60005;
	/** < since v1.1.0.6 NATNL NAT type detect completely */

	// 2013.03.22 Justin Tung Edit
	public static int NATNL_TNL_EVENT_INIT_OK = 60100;
	/** init successfully (since v1.1.0.11) */
	public static int NATNL_TNL_EVENT_INIT_FAILED = 60101;
	/** init failed (since v1.1.0.11) */
	public static int NATNL_TNL_EVENT_MAKECALL_OK = 60104;
	/** make call successfully */
	public static int NATNL_TNL_EVENT_MAKECALL_FAILED = 60105;
	/** make call fail */
	public static int NATNL_TNL_EVENT_HANGUP_OK = 60106;
	/** hangup successfully */
	public static int NATNL_TNL_EVENT_HANGUP_FAILED = 60107;
	/** hangup fail */
	public static int NATNL_TNL_EVENT_DEINIT_OK = 60102;
	/** deinit successfully */
	public static int NATNL_TNL_EVENT_DEINIT_FAILED = 60103;
	/** deinit fail */

	public static int NATNL_API_ID_INIT = 1001;
	public static int NATNL_API_ID_MAKECALL = 1002;
	public static int NATNL_API_ID_HANGUP = 1003;
	public static int NATNL_API_ID_DEINIT = 1004;

}

// implement the abstract callback class
class NatCb extends NatCallback {
	int reg_sip_done = 0;
	RelayInterface natSample = null;

	// To Check the member in Reference Libraries
	NatCb(RelayInterface nat_imp) {
		natSample = nat_imp;
	}

	// the callback functions must be implemented here
	public void on_natnl_tnl_event() {
		// callback to here
		RelayInterface.mCallId = call_id;
		Log.e("Sample", "callback on_natnl_tnl_event alert, callee id = "
				+ RelayInterface.mCallId);
		natSample.NatStatus = this.status_code;
		natSample.NatEventCode = this.event_code;

		Log.e("[RelayHelp]", "callback on_natnl_tnl_event event_code= "
				+ this.event_code);

		natSample.CalleeSDKVersion = this.CalleeSDKVersion;
		natSample.CallerSDKVersion = this.CallerSDKVersion;
		Log.d("ao", "eventCode = " + this.event_code);
		Log.d("ao", "eventText = " + this.event_text);
		Log.d("ao", "statusCode = " + status_code);
		Log.d("ao", "statusText = " + status_text);

		Message m = natSample.m_handler.obtainMessage();
		m.obj = natSample;
		switch (natSample.NAT_API_ID) {
		case 1001:
			if (Natnl_Event.NATNL_TNL_EVENT_INIT_OK == event_code) {
				natSample._WebServiceFunc.GetUpdateProfile("2");

				// Send Message to Handler for processing main thread task.
				m.what = 1001;
				natSample.m_handler.sendMessage(m);

				natSample.m_onAuthListener.CBInit(true);
			} else if (Natnl_Event.NATNL_TNL_EVENT_INIT_FAILED == event_code)
				natSample.m_onAuthListener.CBInit(false);
			break;
		case 1002:
			if (this.event_code == 6) // tunnel disconnected.
			{
				natSample.RelayHangUp();
				natSample.m_onAuthListener.CBMakeCall(false);
			} else if (Natnl_Event.NATNL_TNL_EVENT_MAKECALL_OK == event_code) {
				// Eddy
				// Change Port after make call success.
				if (RelayInterface.bIsNeedTunningPort == true) {
					if (natSample.RTunnelPort() == 0)
						natSample.m_onAuthListener.CBMakeCall(true);
					else
						natSample.m_onAuthListener.CBMakeCall(false);
				} else
					natSample.m_onAuthListener.CBMakeCall(true);
			} else if (Natnl_Event.NATNL_TNL_EVENT_MAKECALL_FAILED == event_code)
				natSample.m_onAuthListener.CBMakeCall(false);
			break;
		case 1003:
			if (Natnl_Event.NATNL_TNL_EVENT_HANGUP_OK == event_code)
				natSample.m_onAuthListener.CBHangUp(true);
			else if (Natnl_Event.NATNL_TNL_EVENT_HANGUP_FAILED == event_code)
				natSample.m_onAuthListener.CBHangUp(false);
			break;
		case 1004:
			if (Natnl_Event.NATNL_TNL_EVENT_DEINIT_OK == event_code) {

				// Send Message to Handler for processing main thread task.
				m.what = 1004;
				natSample.m_handler.sendMessage(m);
				natSample._WebServiceFunc.GetUpdateProfile("0");
				natSample.m_onAuthListener.CBDeInit(true);
			} else if (Natnl_Event.NATNL_TNL_EVENT_DEINIT_FAILED == event_code)
				natSample.m_onAuthListener.CBDeInit(false);
			break;
		default:
			break;
		}

		// below sampel shows how to Call directly
		/*
		 * if(this.event_code == Natnl_Event.NATNL_SIP_EVENT_REG &&
		 * this.status_code == 200){ natSample.MakeCall(natSample.USER_ID,
		 * natSample.CALLEE); }
		 */
	}
}

// implement the NatConfig class
class NatCfg extends NatConfig {
	// To Check the member in Reference Libraries
	NatCfg() {
		// init test data here
		super();
	}

	public void PrintCfg() {

	}
}

class WndHandler extends Handler {
	@Override
	public void handleMessage(Message msg) {
		RelayInterface myClassInstance = (RelayInterface) msg.obj;
		switch (msg.what) {
		case 1001: {
			// If Initialization is successful, setting RelayInterface instance
			// to TimerListener.
			if (myClassInstance.mTM_timer != null) {
				myClassInstance.mTM_timer.StopTimer();
			}
			Log.d("handleMessage", "KeepAliveTimer~~~");
			myClassInstance.mTM_timer = new TimerCtrlBase(myClassInstance,
					180000);
			myClassInstance.mTM_timer.StartTimer();
			break;
		}
		case 1004: {
			// Stop timer of accessing Keep Relay Alive Function.
			myClassInstance.mTM_timer.StopTimer();
		}
			break;
		default:
			break;
		}
		super.handleMessage(msg);
	}
}

public class RelayInterface implements ThreadRunListener, TimerRunListener {
	NatNativeAPI xNatApi;
	NatCfg natcfg = new NatCfg();
	public static int mCallId;
	public String USER_ID = "XXXX";
	public String CALLEE = "0010019000000000000077";
	// 2013.12.13
	public static String CallerSDKVersion;
	public static String CalleeSDKVersion;

	public int NatStatus;
	public int NatEventCode;
	public boolean m_bIsInit = true;
	public int NAT_API_ID = 0;

	// remote and local ports for Relay Service
	public static String[][] m_srv_port = null;

	// Create Instance of relayInterface
	public static RelayInterface _this;
	public static Context _con;

	public static RegistRelayFunc _WebServiceFunc = null;

	// For Auth Finished Callback
	public static onAuthListener m_onAuthListener;

	// Thread var
	protected static ThreadCtrlBase mTH_GetAuth = null;

	// Timer
	protected static TimerCtrlBase mTM_timer = null;

	// Local Handler
	public WndHandler m_handler = null;

	// For Relay Server
	public String ClientMsg = "";
	public String m_userId = "";
	public String m_userPwd = "";
	public String m_userName = "";
	// Function ID
	public static final int WM_GetAuthorizationRelayS = 5005;
	public static final int WM_GetDeviceList = 5006;
	public static final int WM_LogoutRelayS = 5007;
	public static final int WM_Init = 5008;
	public static final int WM_MakeCall = 5010;
	public static final int WM_HangUp = 5011;
	public static final int WM_DeInit = 5012;
	public static final int WM_KeepAlive = 5014;
	public static final int WM_SignUp = 5015;

	public RelayInterface() {
		_this = this;
		m_handler = new WndHandler();
	}

	private void InitTestCfgData(NatCfg natcfg) {
		// int err = NatSetInfo2(mNatCfg);
		natcfg.device_id = CfgDataInit.DEVICE_ID;
		natcfg.device_pwd = CfgDataInit.DEVICE_PWD;
		natcfg.mUpnpCfg.flag = CfgDataInit.UPNP_FLAG;
		natcfg.force_to_use_ice = CfgDataInit.FORCE_TO_USE_ICE;
		natcfg.mLogCfg.log_file_flags = CfgDataInit.LOG_FILE_FLAG;
		natcfg.mLogCfg.log_filename = CfgDataInit.LOG_FILE_PATH;
		natcfg.mLogCfg.log_level = CfgDataInit.LOG_LOG_LEVEL;
		natcfg.max_calls = CfgDataInit.MAX_CALLS;
		// natcfg.sip_srv = CfgDataInit.SIP_SRV;
		natcfg.sip_srv = new String[3];
		natcfg.sip_srv_cnt = 3;
		natcfg.sip_srv[0] = CfgDataInit.SIP_SRV;
		natcfg.sip_srv[1] = CfgDataInit.SIP_SRV2;
		natcfg.sip_srv[2] = CfgDataInit.SIP_SRV3;
		natcfg.stun_srv_cnt = 1;
		natcfg.stun_srv = new String[1];
		natcfg.stun_srv[0] = CfgDataInit.STUN_SRV;
		natcfg.turn_srv_cnt = 2;
		natcfg.turn_srv = new String[2];
		natcfg.turn_srv[0] = CfgDataInit.TURN_SRV;
		natcfg.turn_srv[1] = CfgDataInit.TURN_SRV2;
		natcfg.use_stun = CfgDataInit.USE_STUN;
		natcfg.use_tls = CfgDataInit.USE_TLS;
		natcfg.verify_server = CfgDataInit.VERIFY_SERVER;
		natcfg.use_turn = CfgDataInit.USE_TURN;
		natcfg.mUpnpCfg.user_port_count = CfgDataInit.USER_PORT_CNT;
		natcfg.tnl_timeout_sec = 100;
		natcfg.disable_sdp_compress = 0;
		natcfg.bandwidth_KBs_limit = 0; // KB, 0 for unlimit
		// natcfg.srv_port_count=2;

		for (int i = 0; i < natcfg.mUpnpCfg.user_port_count; i++) {
			natcfg.mUpnpCfg.usr_port[i].local_data = CfgDataInit.LOCAL_DATA[i];
			natcfg.mUpnpCfg.usr_port[i].external_data = CfgDataInit.EXTERNAL_DATA[i];
			natcfg.mUpnpCfg.usr_port[i].local_ctl = CfgDataInit.LOCAL_CTL[i];
			natcfg.mUpnpCfg.usr_port[i].external_ctl = CfgDataInit.EXTERNAL_CTL[i];
		}

		// Eddy
		// natcfg.srv_port_count = CfgDataInit.SRV_PORT_CNT;
		// 2013.04.11 Justin Tung
		/*
		 * natcfg.srv_port_count = CfgDataInit.SRV_PORT_CNT;
		 * //natcfg.natnl_tunnel_ports = new SrvPort[natcfg.srv_port_count];
		 * for(int i = 0; i<natcfg.srv_port_count ;i++){
		 * natcfg.natnl_srv_ports[i].lport = CfgDataInit.LOCAL_PORT[i];
		 * natcfg.natnl_srv_ports[i].rport = CfgDataInit.REMOTE_PORT[i];
		 * 
		 * //natcfg.natnl_tunnel_ports[i] = new SrvPort();
		 * natcfg.natnl_tunnel_ports[i].lport = CfgDataInit.LOCAL_PORT[i];
		 * natcfg.natnl_tunnel_ports[i].rport = CfgDataInit.REMOTE_PORT[i]; }
		 */

		natcfg.srv_port_count = m_srv_port[0].length;
		for (int i = 0; i < natcfg.srv_port_count; i++) {
			natcfg.natnl_srv_ports[i].lport = m_srv_port[0][i];// CfgDataInit.LOCAL_PORT[i];
			natcfg.natnl_srv_ports[i].rport = m_srv_port[1][i];// CfgDataInit.REMOTE_PORT[i];
		}
	}

	// Interface functions -----------------------------------------------------
	public static void SetInterface(Context con) {
		_con = con;
		// Init Relay API
		_this.xNatApi = new NatNativeAPI();
		// NatNativeAPI.LoaAndroidNatLib();
		_this.xNatApi.LoaAndroidNatLib();

		// Init WebService Functions
		_WebServiceFunc = new RegistRelayFunc();
	}

	public static boolean GetRelaySAuth(String userId, String userPwd) {
		_this.m_userId = userId;
		_this.m_userPwd = userPwd;

		if (mTH_GetAuth != null) {
			if (mTH_GetAuth.IsThreadRun() == true) {
				mTH_GetAuth.stopThread();
				mTH_GetAuth = null;
			} else
				mTH_GetAuth = null;
		}
		mTH_GetAuth = new ThreadCtrlBase(WM_GetAuthorizationRelayS, _this, true); // third
		// parameter
		// is
		// true:
		// run
		// once;
		// is
		// false:
		// run
		// loop
		mTH_GetAuth.startThread();

		// RegistRelayFunc.GetRelaySAuthFunc(_con, userId, userPwd);
		return true;
	}

	public static boolean SignUp(String userId, String userPwd, String userName) {
		_this.m_userId = userId;
		_this.m_userPwd = userPwd;
		_this.m_userName = userName;

		if (mTH_GetAuth != null) {
			if (mTH_GetAuth.IsThreadRun() == true) {
				mTH_GetAuth.stopThread();
				mTH_GetAuth = null;
			} else
				mTH_GetAuth = null;
		}
		mTH_GetAuth = new ThreadCtrlBase(WM_SignUp, _this, true);
		mTH_GetAuth.startThread();
		return true;
	}

	public static boolean ListProfile() {
		if (mTH_GetAuth != null) {
			if (mTH_GetAuth.IsThreadRun() == true) {
				mTH_GetAuth.stopThread();
				mTH_GetAuth = null;
			} else
				mTH_GetAuth = null;
		}
		mTH_GetAuth = new ThreadCtrlBase(WM_GetDeviceList, _this, true); // third
		// parameter
		// is
		// true:
		// run
		// once;
		// is
		// false:
		// run
		// loop
		mTH_GetAuth.startThread();

		return true;
	}

	public static boolean LogoutRelayS() {
		if (mTH_GetAuth != null) {
			if (mTH_GetAuth.IsThreadRun() == true) {
				mTH_GetAuth.stopThread();
				mTH_GetAuth = null;
			} else
				mTH_GetAuth = null;
		}
		mTH_GetAuth = new ThreadCtrlBase(WM_LogoutRelayS, _this, true); // third
		// parameter
		// is
		// true:
		// run
		// once;
		// is
		// false:
		// run
		// loop
		mTH_GetAuth.startThread();

		return true;
	}

	// Eddy
	public static boolean RelayInit(String[][] srv_port, int num_Port) {
		// Srv_port Definition

		m_srv_port = new String[2][num_Port];// new Srv_Port_Info[num_Port];
		for (int i = 0; i < num_Port; i++) {
			m_srv_port[0][i] = srv_port[0][i];
			m_srv_port[1][i] = srv_port[1][i];
		}

		if (mTH_GetAuth != null) {
			if (mTH_GetAuth.IsThreadRun() == true) {
				mTH_GetAuth.stopThread();
				mTH_GetAuth = null;
			} else
				mTH_GetAuth = null;
		}

		mTH_GetAuth = new ThreadCtrlBase(WM_Init, _this, true); // third
		// parameter is
		// true: run
		// once; is
		// false: run
		// loop
		mTH_GetAuth.startThread();
		return true;
	}

	// Eddy
	public static boolean bIsNeedTunningPort = false;

	public static boolean RelayMakeCall(String user_id, String call_id,
			String[][] srv_port, int num_Port) {
		_this.USER_ID = user_id;
		_this.CALLEE = call_id;

		// Srv_port Redefinition
		if (num_Port == 0)
			bIsNeedTunningPort = false;
		else {
			bIsNeedTunningPort = true;

			if (srv_port == null || num_Port == 0)
				m_srv_port = null;
			else {
				m_srv_port = new String[2][num_Port];// new
				// Srv_Port_Info[num_Port];
				for (int i = 0; i < num_Port; i++) {
					m_srv_port[0][i] = srv_port[0][i];
					m_srv_port[1][i] = srv_port[1][i];
				}
			}
		}

		if (mTH_GetAuth != null) {
			if (mTH_GetAuth.IsThreadRun() == true) {
				mTH_GetAuth.stopThread();
				mTH_GetAuth = null;
			} else
				mTH_GetAuth = null;
		}
		mTH_GetAuth = new ThreadCtrlBase(WM_MakeCall, _this, true); // third
		// parameter
		// is true:
		// run once;
		// is false:
		// run loop
		mTH_GetAuth.startThread();
		return true;
	}

	public static boolean RelayHangUp() {
		if (mTH_GetAuth != null) {
			if (mTH_GetAuth.IsThreadRun() == true) {
				mTH_GetAuth.stopThread();
				mTH_GetAuth = null;
			} else
				mTH_GetAuth = null;
		}
		mTH_GetAuth = new ThreadCtrlBase(WM_HangUp, _this, true); // third
		// parameter
		// is true:
		// run once;
		// is false:
		// run loop
		mTH_GetAuth.startThread();
		return true;
	}

	public static boolean RelayDeInit() {
		if (mTH_GetAuth != null) {
			if (mTH_GetAuth.IsThreadRun() == true) {
				mTH_GetAuth.stopThread();
				mTH_GetAuth = null;
			} else
				mTH_GetAuth = null;
		}
		mTH_GetAuth = new ThreadCtrlBase(WM_DeInit, _this, true); // third
		// parameter
		// is true:
		// run once;
		// is false:
		// run loop
		mTH_GetAuth.startThread();
		return true;
	}

	public static void ClientSocket(String strCaption) {
		_this.SendSocketToRemote(strCaption);
	}

	// Interface functions End
	// ---------------------------------------------------------------------

	// Inner Functions
	public int RInit() {
		NAT_API_ID = Natnl_Event.NATNL_API_ID_INIT;

		// Set Config
		_this.InitTestCfgData(natcfg);
		/* 2013.03.22 Justin Tung */
		natcfg = _WebServiceFunc.SetConfigFunc(natcfg);
		_this.SetCfg((NatConfig) natcfg);

		// Start Init
		NatCb natcb = new NatCb(_this);
		natcb.user_id = "";
		natcb.device_id = natcfg.device_id;
		return _this.Init(natcb);
	}

	public int RMakeCall(String userId, String deviceid) {
		NAT_API_ID = Natnl_Event.NATNL_API_ID_MAKECALL;
		return _this.MakeCall(userId, deviceid, 100);
	}

	public int RTunnelPort() {
		int result = 0;
		// Step 1 ------- Remove Old srv_port
		result = xNatApi.NatTunnelPort(mCallId, 2, natcfg.srv_port_count,
				natcfg);
		if (result != 0)
			return -1;

		// Step 2 ------- if user input srvport is not empty, write new port
		// into natcfg.
		int SrvPortCnt = natcfg.srv_port_count;
		if (m_srv_port != null) {
			SrvPortCnt = m_srv_port[0].length;
			natcfg.srv_port_count = SrvPortCnt;
			for (int i = 0; i < SrvPortCnt; i++) {
				natcfg.natnl_tunnel_ports[i].lport = m_srv_port[0][i];
				natcfg.natnl_tunnel_ports[i].rport = m_srv_port[1][i];

				natcfg.natnl_srv_ports[i].lport = m_srv_port[0][i];
				natcfg.natnl_srv_ports[i].rport = m_srv_port[1][i];
			}
			// int call_id, int action, int tnl_port_count, struct
			// natnl_srv_port tnl_port
			result = xNatApi.NatTunnelPort(mCallId, 1, SrvPortCnt, natcfg);
			Log.d("ChangeTunnelPort", String.valueOf(result));
		}

		return result;
	}

	public int RHangUp() {
		NAT_API_ID = Natnl_Event.NATNL_API_ID_HANGUP;
		return _this.HangUp(mCallId);
	}

	public int RDeInit() {
		NAT_API_ID = Natnl_Event.NATNL_API_ID_DEINIT;
		return _this.Deinit();
	}

	protected int SetCfg(NatConfig natcfg) {
		return xNatApi.NatSetCfg(natcfg);
	}

	protected int Init(NatCallback natcb) {
		// return xNatApi.NatLibInit(natcb);
		return xNatApi.NatLibInit(natcb, natcfg);
	}

	protected int MakeCall(String user_id, String callee, int timeout) {
		// 2013.12.13
		try {

			return xNatApi.NatMakeCall(user_id, callee, timeout,
					natcfg.srv_port_count, natcfg.natnl_srv_ports);

		} catch (Exception e) {
			Log.d("makecall", "[MakeCall Error]");
			e.printStackTrace();
			return 1;
		}

	}

	protected int HangUp(int Callid) {
		return xNatApi.NatHangupcall(Callid);
	}

	protected int Deinit() {
		return xNatApi.NatDeinit();
	}

	private void SendSocketToRemote(final String SocketCaption) {
		new Thread() {
			public void run() {

				Socket socket = null;
				// Send 6666, receive 8888.
				InetSocketAddress isa = new InetSocketAddress("127.0.0.1",
						Integer.valueOf(natcfg.natnl_tunnel_ports[0].lport));
				DataOutputStream dataOutputStream = null;
				DataInputStream dataInputStream = null;
				Log.v("SendToRemote", "Send!!!!!!!!!!!!!!!!!!!!!!!!");

				try {
					socket = new Socket();
					socket.connect(isa);
					// socket.setSoTimeout(1);
					dataOutputStream = new DataOutputStream(
							socket.getOutputStream());
					dataOutputStream.writeBytes(SocketCaption);
					dataInputStream = new DataInputStream(
							socket.getInputStream());

					byte buf[] = new byte[1024];
					int avalible = dataInputStream.read(buf);
					byte[] result;
					String strRead = "";

					if (avalible > 0) {
						result = new byte[avalible];
						for (int i = 0; i < avalible; i++)
							result[i] = buf[i];

						strRead = new String(result);
						Log.v("SendBackFromRemote-------", strRead);
						Log.v("SendBackMsgLength",
								String.valueOf(strRead.length()));
					}

					m_onAuthListener.CBClientSocket(strRead);

					// CMsg.setText(dataInputStream.readUTF());
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}

				finally {

					if (dataOutputStream != null) {
						try {
							dataOutputStream.close();
						} catch (IOException e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						}
					}

					if (dataInputStream != null) {
						try {
							dataInputStream.close();
						} catch (IOException e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						}
					}

					if (socket != null) {
						try {
							socket.close();
						} catch (IOException e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						}
					}

				}
			}
		}.start();
	}

	public void ThreadRun(int iID) {
		// TODO Auto-generated method stub
		if (iID == WM_GetAuthorizationRelayS) {
			boolean bIsTrue = _WebServiceFunc.GetRelaySAuthFunc(_con, m_userId,
					m_userPwd);
			m_onAuthListener.GetAuthFinished(bIsTrue);
			// this.mOnNATListener.onAuthFinished(bIsTrue);
		} else if (iID == WM_GetDeviceList) {
			List<DevListInfo> new_list = _WebServiceFunc.ListProfileFunc();
			m_onAuthListener.ListProfileFinished(new_list);
		} else if (iID == WM_LogoutRelayS) {
			boolean bValue = _WebServiceFunc.LogOutRelaySFunc();
			m_onAuthListener.LogoutFinished(bValue);
		} else if (iID == WM_Init) {
			int iValue = _this.RInit();
		} else if (iID == WM_MakeCall) {
			int iValue = _this.RMakeCall(USER_ID, CALLEE);
		} else if (iID == WM_HangUp) {
			int iValue = _this.RHangUp();
		} else if (iID == WM_DeInit) {
			int bValue = _this.RDeInit();
		} else if (iID == WM_SignUp) {
			SignUpStatus bValue = _WebServiceFunc.SignUp(_con, m_userId,
					m_userPwd, m_userName);
			m_onAuthListener.GetSignUp(bValue);
		}
	}

	@Override
	public void TimerRun() {
		// TODO Auto-generated method stub

		_WebServiceFunc.GetKeepAliveFunc();

	}

}
